/*
 *
 * Copyright (C) 2012 Walter Lütgenau
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */
package offset.nodes.server.servlet.book.content;

import java.io.ByteArrayOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import offset.nodes.Constants;
import offset.nodes.client.model.HttpUtils;
import offset.nodes.client.virtual.model.jcr.PrintHandler;
import offset.nodes.server.servlet.book.Book;
import offset.nodes.server.servlet.book.provider.NodeProvider;
import offset.nodes.server.servlet.book.NameBuilder;

/**
 * Substitute a value
 * @author Walter L�tgenau
 */
interface Substituter {

    public String substitute(String value);
}

/**
 * Represents a page.
 * 
 * @author Walter L�tgenau
 */
public class Page extends Resource implements Cloneable {

    private String name;
    private int level;
    private List<BookHyperlink> sublinks = new ArrayList<BookHyperlink>();
    private HashMap<String, Resource> resources = new HashMap<String, Resource>();
    private NodeProvider nodeProvider;
    boolean followLinks;
    BookPageType type;

    public Page(Book book, int level, String repositoryRef, String content, NodeProvider nodeProvider, boolean followLinks, BookPageType type) throws Exception {
        this(book, level, repositoryRef, content, nodeProvider, followLinks, type, null);
        this.nodeProvider = nodeProvider;
    }

    public Page(Book book, int level, String repositoryRef, String content, NodeProvider nodeProvider, boolean followLinks, BookPageType type, HashMap<String, String> substitutions) throws Exception {
        super(repositoryRef);
        this.level = level;
        this.followLinks = followLinks;
        this.type = type;
        setContent(new StringContent(content));

        init(book, repositoryRef, content, nodeProvider, substitutions);
    }

    /**
     * Parse or create the other member.
     * 1. Process the header: Extract the stylesheet files, add them to resources. Create a new header in XHTML.
     * 2. Process the body:
     * 2.1 Add all images to the resource list, substitute the corresponding elements using a new location, obtained from the NameBuilder.
     * 2.2 Extract the hyperlinks leading to virtual pages, if present in a HTML collection, i.a. a table. Substitute the hyperlinks with
     *       book internal hyperlinks obtained from the NameBuilder. Parse the corresponding URLs for the UUID, set it to repositoryRef of the
     *       page.
     *
     * The conditions for a HTML collection are:
     * 1. A "href" attribute with a URL using the "contentType" parameter
     * 2. A parent element with an "n-data" attribute, that is a table row.
     * 
     * @param the reference to the page. Either a path or a query URL.
     * @param content
     * @param nameBuilder transforms the repository references into book specific internal references.
     */
    protected void init(Book book, String reference, String content, NodeProvider nodeProvider, HashMap<String, String>  substitutions) throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        PageParser parser = new PageParser(book, new PrintHandler(out), nodeProvider, this, followLinks);
        if (substitutions != null)
            parser.setSubstitutions(substitutions);
        parser.parse(new String(content.getBytes()));

        setContent(new StringContent(out.toString()));

        URL url;
        try {
            url = new URL(reference);
            if (url.getQuery() != null) {
                HashMap<String, String> parameters = HttpUtils.getParameters(reference);
                if (parameters.get(Constants.PAR_DATA_REFERENCE) != null)
                    setRepositoryRef(parameters.get(Constants.PAR_DATA_REFERENCE));
                else
                    setRepositoryRef(reference); // should not happen
            } else
                setRepositoryRef(reference);
            setBookRef(book.getNameBuilder().buildPageName(getRepositoryRef()));
        } catch (MalformedURLException e) {
            // a path
            setRepositoryRef(reference);
            setBookRef(book.getNameBuilder().buildPageName(getRepositoryRef()));
        }
    }

    public int getLevel() {
        return level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<BookHyperlink> getSublinks() {
        return sublinks;
    }

    public BookPageType getType() {
        return type;
    }

    public Collection<Resource> getResources() {
        return resources.values();
    }

    public void addResource(Resource resource) {
        resources.put(resource.getRepositoryRef(), resource);
    }
    
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
